package com.egg.basic.service.pay.factory.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayResponse;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.egg.basic.config.pay.PayAliConfig;
import com.egg.basic.entity.pay.PayRecord;
import com.egg.basic.entity.pay.RefundRecord;
import com.egg.basic.enums.pay.ClientTypeEnum;
import com.egg.basic.enums.pay.PayTypeEnum;
import com.egg.basic.enums.pay.TradeStateEnum;
import com.egg.basic.model.rabbit.PayRabbitSender;
import com.egg.basic.rabbitmq.sender.PaySender;
import com.egg.basic.service.pay.factory.IPayFactory;
import com.egg.basic.service.pay.impl.PayRecordServiceImpl;
import com.egg.common.core.exception.CustomException;
import com.egg.common.core.model.response.ResponseData;
import com.egg.common.util.HttpServletUtil;
import com.ijpay.alipay.AliPayApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

/**
 * 支付宝消息处理类
 */
@Slf4j
@Service
public class PayFactoryAli implements IPayFactory, InitializingBean {


    @Autowired
    private PayRecordServiceImpl payRecordService;
    @Autowired(required = false)
    private PayAliConfig payAliConfig;
    @Autowired
    private PaySender paySender;


    @Override
    public void afterPropertiesSet() {
        if (null != payAliConfig) {
            container.put(PayTypeEnum.ALI.getCode(), this);
        }
    }


    /**
     * 转换金额
     * -- 分转换为元
     *
     * @return
     */
    private BigDecimal convertAmount(Long amount) {
        BigDecimal totalFee = new BigDecimal(amount).divide(new BigDecimal(100));
        return totalFee;
    }

    private String pcPay(PayRecord pr) {
        AlipayTradePagePayModel model = new AlipayTradePagePayModel();
        model.setProductCode("FAST_INSTANT_TRADE_PAY");
        model.setOutTradeNo(pr.getId().toString());
        model.setTotalAmount(convertAmount(pr.getAmount()).toString());
        model.setSubject(pr.getSubject());

        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setBizModel(model);
        request.setNotifyUrl(payAliConfig.getFullPayNotifyUrl());
        try {
            AlipayResponse alipayResponse = AliPayApi.pageExecute(request, "GET");
            if (alipayResponse.isSuccess()) {
                return alipayResponse.getBody();
            } else {
                log.error("支付宝拉起PC支付失败 ", alipayResponse.getMsg());
                throw new CustomException(alipayResponse.getMsg());
            }
        } catch (AlipayApiException e) {
            log.error("支付宝拉起PC支付失败 ", e);
            throw new CustomException(e.getErrMsg());
        }
    }

    private String appPay(PayRecord pr) {
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setProductCode("QUICK_MSECURITY_PAY");
        model.setOutTradeNo(pr.getId().toString());
        model.setTotalAmount(convertAmount(pr.getAmount()).toString());
        model.setSubject(pr.getSubject());
        try {
            AlipayResponse alipayResponse = AliPayApi.appPayToResponse(model, payAliConfig.getFullPayNotifyUrl());
            if (alipayResponse.isSuccess()) {
                return alipayResponse.getBody();
            } else {
                log.error("支付宝拉起APP支付失败 ", alipayResponse.getMsg());
                throw new CustomException(alipayResponse.getMsg());
            }
        } catch (AlipayApiException e) {
            log.error("支付宝拉起APP支付失败 ", e);
            throw new CustomException(e.getErrMsg());
        }
    }

    private String wapPay(PayRecord pr) {
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        model.setProductCode("QUICK_WAP_PAY");
        model.setOutTradeNo(pr.getId().toString());
        model.setTotalAmount(convertAmount(pr.getAmount()).toString());
        model.setSubject(pr.getSubject());

        AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
        request.setBizModel(model);
        request.setNotifyUrl(payAliConfig.getFullPayNotifyUrl());
        try {
            AlipayResponse alipayResponse = AliPayApi.pageExecute(request, "GET");
            if (alipayResponse.isSuccess()) {
                return alipayResponse.getBody();
            } else {
                log.error("支付宝拉起WAP支付失败 ", alipayResponse.getMsg());
                throw new CustomException(alipayResponse.getMsg());
            }
        } catch (AlipayApiException e) {
            log.error("支付宝拉起WAP支付失败 ", e);
            throw new CustomException(e.getErrMsg());
        }
    }

    /**
     * 支付宝支付
     *
     * @param pr
     * @return
     */
    @Override
    public ResponseData<String> add(PayRecord pr) {
        ClientTypeEnum clientTypeEnum = ClientTypeEnum.getByCode(pr.getClientType());
        switch (clientTypeEnum) {
            case PC:
                return ResponseData.success(pcPay(pr));
            case APP:
                return ResponseData.success(appPay(pr));
            case WAP:
                return ResponseData.success(wapPay(pr));
            default:
                return ResponseData.error("客户端支付类型不支持");
        }
    }

    /**
     * 退款
     *
     * @param refund
     * @return
     */
    @Override
    public ResponseData<String> refund(RefundRecord refund) {
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
        model.setOutTradeNo(refund.getPayRecordId().toString());
        model.setTradeNo(refund.getTradeNo());
        model.setRefundAmount(convertAmount(refund.getAmount()).toString());
        model.setRefundReason(refund.getRemark());
        try {
            AlipayTradeRefundResponse response = AliPayApi.tradeRefundToResponse(model);
            if (response.isSuccess()) {
                return ResponseData.success(response.getBody());
            } else {
                return ResponseData.error(response.getMsg());
            }
        } catch (AlipayApiException e) {
            return ResponseData.error(e.getErrMsg());
        }
    }

    /**
     * 支付宝支付回调
     *
     * @return
     */
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void payNotify() {
        HttpServletRequest request = HttpServletUtil.getHttpServletRequest();
        if (null == request) {
            return;
        }
        Map<String, String> params = AliPayApi.toMap(request);
        boolean verifyResult;
        try {
            verifyResult = AlipaySignature.rsaCheckV1(params, payAliConfig.getPublicKey(), payAliConfig.getCharset(), payAliConfig.getSignType());
        } catch (Exception e) {
            log.error("支付宝回调 参数 {} 验签异常 {}", JSONObject.toJSONString(params), e);
            verifyResult = false;
        }
        log.debug("支付回调 参数 {} 验签结果 {}", JSONObject.toJSONString(params), verifyResult);
        if (!verifyResult) {
            return;
        }
        //支付记录主表ID
        String outTradeNo = params.get("out_trade_no");
        Optional<PayRecord> payRecordOpt = payRecordService.baseFindById(outTradeNo);
        if (!payRecordOpt.isPresent()) {
            return;
        }
        PayRecord payRecord = payRecordOpt.get();
        if (!Objects.equals(payRecord.getTradeState(), TradeStateEnum.WAIT.getCode())) {
            return;
        }
        /*
            WAIT_BUYER_PAY:交易创建(不触发通知),
            TRADE_CLOSED:交易关闭(未付款交易超时关闭或支付完成后全额退款)
            TRADE_SUCCESS:交易支付成功(交易支付成功,可退款)
            TRADE_FINISHED:交易完成(交易结束,不可退款)
        */
        String trade_status = params.get("trade_status");
        if ("TRADE_SUCCESS".equalsIgnoreCase(trade_status)) {
            payRecord.setTradeState(TradeStateEnum.SUCCESS.getCode());
        } else {
            payRecord.setTradeState(TradeStateEnum.FAIL.getCode());
            payRecord.setRemark(JSON.toJSONString(params));
        }
        String tradeNo = params.get("trade_no");
        payRecord.setTradeNo(tradeNo);
        payRecordService.baseEdit(payRecord);

        //支付成功发送成功通知
        if (Objects.equals(payRecord.getTradeState(), TradeStateEnum.SUCCESS.getCode())) {
            PayRabbitSender sender = new PayRabbitSender();
            sender.setBusinessType(payRecord.getBusinessType());
            sender.setBusinessId(payRecord.getBusinessId());
            paySender.paySuccess(sender);
        }

    }


}
